package com.akoj.anmu.service.impl;

import com.akoj.anmu.common.ResponseCode;
import com.akoj.anmu.exception.BusinessException;
import com.akoj.anmu.utils.AlgorithmUtils;
import com.akoj.model.domain.dto.user.UserRegisterRequest;
import com.akoj.model.domain.dto.user.UserUpdateRequest;
import com.akoj.model.domain.vo.LoginUserVO;
import com.akoj.model.domain.vo.UserVO;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.akoj.model.domain.entity.User;
import com.akoj.anmu.service.UserService;
import com.akoj.anmu.mapper.UserMapper;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import javafx.util.Pair;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.configurationprocessor.json.JSONArray;
import org.springframework.boot.configurationprocessor.json.JSONException;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import static com.akoj.anmu.constant.UserConstant.ADMIN_ROLE;
import static com.akoj.anmu.constant.UserConstant.USER_STORE;

/**
 * 用户服务实现类
 * @author LENOVO
 * @description 针对表【user】的数据库操作Service实现
 * @createDate 2024-10-14 20:20:26
 */
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User>
        implements UserService{

    @Resource
    private UserMapper userMapper;

    @Resource
    private RedisTemplate redisTemplate;

    private static final String ImageFilePath = "D:\\编程导航\\伙伴匹配\\anmu-backend\\src\\main\\java\\com\\akoj\\anmu\\ImageFiles\\";

    //盐
    private static final String SALT = "akme";
    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Override
    public Long UserRegister(UserRegisterRequest userRegisterRequest) {
        String userAccount = userRegisterRequest.getUserAccount();
        String userPassword = userRegisterRequest.getUserPassword();
        String checkPassword = userRegisterRequest.getCheckPassword();
        List<String> tags = userRegisterRequest.getTags();
        String avatarUrl = userRegisterRequest.getAvatarUrl();
        String nickName = userRegisterRequest.getNickName();
        String userEmail = userRegisterRequest.getUserEmail();
        String profile = userRegisterRequest.getProfile();
        //账号密码不能为空
        if(StringUtils.isAnyBlank(userAccount,userPassword,checkPassword)){
            throw new BusinessException(ResponseCode.PARAMS_ERROR,"账号密码不能为空");
        }
        //检查密码是否一致
        if(!userPassword.equals(checkPassword)){
            throw new BusinessException(ResponseCode.PARAMS_ERROR,"两次输入的密码不一致");
        }
        //邮箱不能为空
        if(StringUtils.isBlank(userEmail)){
            throw new BusinessException(ResponseCode.PARAMS_ERROR,"邮箱不能为空");
        }
        //账号不能少于4位，密码不能少于8位
        if(userAccount.length()<4||userPassword.length()<8||checkPassword.length()<8){
            throw new BusinessException(ResponseCode.PARAMS_ERROR,"账号不能少于4位，密码不能少于8位");
        }
        //账号不能包含特殊字符
        String validPattern = "[`~!@#$%^&*()+=|{}':;',\\\\[\\\\].<>/?~！@#￥%……&*（）——+|{}【】‘；：”“’。，、？]";
        Pattern compile = Pattern.compile(validPattern);
        if(compile.matcher(userAccount).find()){
            throw new BusinessException(ResponseCode.PARAMS_ERROR,"账号不能包含特殊字符");
        }
        //密码和校验密码必须相同
        if(!userPassword.equals(checkPassword)){
            throw new BusinessException(ResponseCode.PARAMS_ERROR,"密码和校验密码必须相同");
        }
        //账户不能重复
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.eq("userAccount",userAccount);
        User user = userMapper.selectOne(wrapper);
        if(user != null){
            throw new BusinessException(ResponseCode.PARAMS_ERROR,"注册账户重复");
        }

        //校验成功，对密码进行加密
        String encodePassword = DigestUtils.md5DigestAsHex((SALT + userPassword).getBytes());

        User handleUser = new User();
        handleUser.setUserAccount(userAccount);
        handleUser.setPassword(encodePassword);
        int i = (int) (Math.random() * 5) + 1;
        handleUser.setAvatarUrl(ImageFilePath + "user" + i + ".png");
        handleUser.setNickName(nickName);
        handleUser.setUserEmail(userEmail);
        //如果用户选择了标签，存入标签
        if(!tags.isEmpty()){
            // 创建 ObjectMapper 实例
            ObjectMapper objectMapper = new ObjectMapper();
            // 将 tags 列表转换为 JSON 字符串
            try {
                String tagsJson = objectMapper.writeValueAsString(tags);
                handleUser.setTags(tagsJson);
            } catch (JsonProcessingException e) {
                throw new RuntimeException(e);
            }
        }
        if(profile != null)
            handleUser.setProfile(profile);
        handleUser.setCreateTime(new Date());
        handleUser.setUpdateTime(new Date());

        boolean save = this.save(handleUser);
        if(!save){
            throw new BusinessException(ResponseCode.PARAMS_ERROR,"注册失败,系统错误");
        }
        return handleUser.getId();
    }

    @Override
    public LoginUserVO doLogin(String userAccount, String userPassword, HttpServletRequest request) {
        //账号密码不能为空
        if(StringUtils.isAnyBlank(userAccount,userPassword)){
            throw new BusinessException(ResponseCode.PARAMS_ERROR,"账号密码不能为空");
        }
        //账号不能少于4位，密码不能少于8位
        if(userAccount.length()<4||userPassword.length()<8){
            throw new BusinessException(ResponseCode.PARAMS_ERROR,"账号不能少于4位，密码不能少于8位");
        }
        //账号不能包含特殊字符
        String validPattern = "[`~!@#$%^&*()+=|{}':;',\\\\[\\\\].<>/?~！@#￥%……&*（）——+|{}【】‘；：”“’。，、？]";
        Pattern compile = Pattern.compile(validPattern);
        if(compile.matcher(userAccount).find()){
            throw new BusinessException(ResponseCode.PARAMS_ERROR,"账号不能包含特殊字符");
        }

        //检测密码是否正确
        //将原密码进行加密
        String mdedPassword = DigestUtils.md5DigestAsHex((SALT + userPassword).getBytes());
        //查询数据库
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.eq("userAccount",userAccount);
        wrapper.eq("password", mdedPassword);
        User user = userMapper.selectOne(wrapper);
        if(user == null){
            throw new BusinessException(ResponseCode.PARAMS_ERROR,"密码错误");
        }

        //构建用户脱敏信息
        LoginUserVO loginUserVO = this.getLoginUserVO(user);

        //保存用户登录态 会同步到redis中
        request.getSession().setAttribute(USER_STORE,loginUserVO);

        return loginUserVO;
    }

    @Override
    public List<UserVO> searchUsersByNickName(String nickName) {
        //查询数据
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.like("nickName",nickName);
        List<User> userList = this.list(wrapper);
        //构建脱敏数据
        List<UserVO> userVOList = userList.stream().map(this::getUserVO).collect(Collectors.toList());
        return userVOList;
    }

    @Override
    public Boolean deleteUserById(Long id) {
        return this.removeById(id);
    }

    @Override
    public Boolean doLogout(HttpServletRequest request) {
        Object attribute = request.getSession().getAttribute(USER_STORE);
        if(attribute == null){
            return false;
        }
        //清除用户登录态
        request.getSession().removeAttribute(USER_STORE);
        return true;
    }

    @Override
    public List<UserVO> searchUsersByTags(List<String> tags,  LoginUserVO currentUser) {
        //查询数据
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        for(String tag : tags){
            wrapper = wrapper.like("tags",tag);
        }
        List<User> Userlist = this.list(wrapper);
        if(Userlist == null || Userlist.isEmpty()){
            throw new BusinessException(ResponseCode.NOT_FOUND,"未查询到任何结果");
        }
        //过滤掉自己
        List<User> handledUserList = Userlist.stream().filter(user -> !user.getId().equals(currentUser.getId())).collect(Collectors.toList());
        //构建脱敏数据
        List<UserVO> userVOList = handledUserList.stream().map(this::getUserVO).collect(Collectors.toList());
        return userVOList;
    }

    @Override
    public LoginUserVO getCurrentUser(HttpServletRequest request) {
        Object attribute = request.getSession().getAttribute(USER_STORE);
        LoginUserVO loginUser = (LoginUserVO) attribute;
        if(loginUser == null){
            throw new BusinessException(ResponseCode.NOT_LOGIN, "未登录");
        }
        return loginUser;
    }

    /**
     * 获取登录用户脱敏视图对象
     */
    public LoginUserVO getLoginUserVO(User user){
        if(user == null){
            return null;
        }
        List<String> tagsList = new ArrayList<>();
        String tagsStr = user.getTags();
        if(!"".equals(tagsStr) && tagsStr != null){
            try {
                JSONArray jsonArray = new JSONArray(tagsStr);
                for(int i=0; i<jsonArray.length(); i++){
                    tagsList.add(jsonArray.getString(i));
                }
            } catch (JSONException e) {
                throw new BusinessException(ResponseCode.SERVER_ERROR,"服务出错");
            }
        }
        LoginUserVO loginUserVO = new LoginUserVO();
        BeanUtils.copyProperties(user,loginUserVO);
        if(!tagsList.isEmpty()){
            loginUserVO.setTags(tagsList);
        }
        return loginUserVO;
    }

    /**
     * 获取用户脱敏视图对象
     */
    public UserVO getUserVO(User user){
        if(user == null){
            return null;
        }
        List<String> tagsList = new ArrayList<>();
        String tagsStr = user.getTags();
        if(!"".equals(tagsStr) && tagsStr != null){
            try {
                JSONArray jsonArray = new JSONArray(tagsStr);
                for(int i=0; i<jsonArray.length(); i++){
                    tagsList.add(jsonArray.getString(i));
                }
            } catch (JSONException e) {
                throw new BusinessException(ResponseCode.SERVER_ERROR,"服务出错");
            }
        }
        UserVO userVO = new UserVO();
        BeanUtils.copyProperties(user,userVO);
        if(!tagsList.isEmpty()){
            userVO.setTags(tagsList);
        }
        return userVO;
    }

    /**
     * 判断是否登录以及权限是否是管理员
     * @param request 请求
     * @return 判断结果
     */
    public Boolean isAdmin(HttpServletRequest request){
        //判断是否登录以及权限是否满足
        Object attribute = request.getSession().getAttribute(USER_STORE);
        LoginUserVO loginUser = (LoginUserVO) attribute;
        if (loginUser == null || loginUser.getUserRole() != ADMIN_ROLE) {
            return false;
        }
        return true;
    }

    @Override
    public UserVO updateUser(UserUpdateRequest userUpdateRequest, LoginUserVO loginUser) {
        //判断更新的昵称是否重复
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.eq("nickName",userUpdateRequest.getNickName());
        User one = this.getOne(wrapper);
        if(one != null){
            throw new BusinessException(ResponseCode.PARAMS_ERROR,"昵称重复");
        }
        //执行更新逻辑
        userUpdateRequest.setId(loginUser.getId());
        User user = new User();
        BeanUtils.copyProperties(userUpdateRequest,user);
        boolean update = this.updateById(user);
        if(!update){
            throw new BusinessException(ResponseCode.SERVER_ERROR,"服务内部出错");
        }
        //返回脱敏信息
        return this.getUserVO(user);
    }

    @Override
    public List<UserVO> searchRecommendUsers(HttpServletRequest request, long pageNum, long pageSize) {
        //判断是否登录
        LoginUserVO currentUser = this.getCurrentUser(request);
        List<UserVO> userVOList = new ArrayList<>();
        ValueOperations<String,Object> valueOperations = redisTemplate.opsForValue();
        String redisKey = String.format("anmu:user:recommend:%s:%s",currentUser.getId(), pageNum);
        //如果缓存中有数据，先从缓存拿
        List<User> Userpage = (List<User>) valueOperations.get(redisKey);
        if(Userpage != null){
            if(Userpage.isEmpty()){
                throw new BusinessException(ResponseCode.NOT_FOUND,"未查询到任何结果");
            }
            //构建脱敏数据
            userVOList = Userpage.stream().map(this::getUserVO).collect(Collectors.toList());
        }
        //缓存中没数据，查数据库
        else{
            //分页查询
            QueryWrapper<User> wrapper = new QueryWrapper<>();
            Page<User> page = new Page<>(pageNum, pageSize);
            Page<User> pagedUser = this.page(page, wrapper);
            if(pagedUser == null){
                throw new BusinessException(ResponseCode.NOT_FOUND,"未查询到任何结果");
            }
            //构建脱敏数据
            List<User> userList = pagedUser.getRecords();
            if(userList == null || userList.isEmpty()){
                throw new BusinessException(ResponseCode.NOT_FOUND,"未查询到任何结果");
            }
            //过滤掉自己
            List<User> handledUserList = userList.stream().filter(user -> !user.getId().equals(currentUser.getId())).collect(Collectors.toList());
            userVOList = handledUserList.stream().map(this::getUserVO).collect(Collectors.toList());
            //存入缓存，设置过期时间24小时
            valueOperations.set(redisKey, userVOList, 30, TimeUnit.SECONDS);
        }
        return userVOList;
    }

    @Override
    public List<UserVO> matchUsers(LoginUserVO currentUser) {
        //判断是否登录
        if(currentUser == null){
            throw new BusinessException(ResponseCode.NOT_LOGIN,"未登录");
        }

        //获取到登录用户的标签列表
        List<String> loginUserTagsList = currentUser.getTags();
        //查询数据库中的其他用户的标签列表
        QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
        userQueryWrapper.select("id","tags");
        List<User> userList = this.list(userQueryWrapper);
        List<Pair<User,Integer>> userToDistanceList = new ArrayList<>();
        for(User user : userList){
            //过滤掉自己
            if(user.getId().equals(currentUser.getId())){
                continue;
            }
            String tags = user.getTags();
            List<String> userTagsList = new ArrayList<>();
            try {
                JSONArray jsonArray = new JSONArray(tags);
                for(int i=0; i<jsonArray.length(); i++){
                    userTagsList.add(jsonArray.getString(i));
                }
                //获取登录用户标签和其他用户标签的编辑距离，编辑距离越小，说明越相似
                int distance = AlgorithmUtils.minDistance(loginUserTagsList, userTagsList);
                //每个用户与当前用户的编辑距离
                userToDistanceList.add(new Pair<>(user, distance));
            } catch (Exception e) {
                throw new BusinessException(ResponseCode.SERVER_ERROR, "服务内部错误");
            }
        }
        //对userToDistanceList做排序，编辑距离越小，说明相似度越高，就排到前面
        userToDistanceList.sort((a,b) -> a.getValue() - b.getValue());
        List<UserVO> userVOList = new ArrayList<>();
        for(Pair<User, Integer> pair : userToDistanceList){
            QueryWrapper<User> wrapper = new QueryWrapper<>();
            wrapper.eq("id",pair.getKey().getId());
            User user = this.getOne(wrapper);
            UserVO userVO = this.getUserVO(user);
            userVOList.add(userVO);
        }
        return userVOList;
    }
}




